/*
 * MINIX 3 specific settings for lwIP.  We also define the settings that are
 * most important to us, even if they do not deviate from their defaults in
 * lwip/opt.h from the lwIP distribution.
 */
#ifndef LWIP_LWIPOPTS_H
#define LWIP_LWIPOPTS_H

/*
 * We use only the core API of lwIP.  As such, we do not use any of its
 * netconn, socket, mailbox, threading, synchronization, protection (etc)
 * support.  We do need lwIP to manage its own timers.
 */
#define NO_SYS                          1
#define LWIP_TIMERS                     1
#define SYS_LIGHTWEIGHT_PROT            0

/*
 * The summary of our memory model is that we use lwIP's model of static pool
 * preallocation for all objects known to lwIP, and a custom memory pool
 * implementation for all other types of allocations.  The custom memory pool
 * allocates buffers of (up to) a fixed length (currently 512 bytes) from
 * a small static memory pool and possibly in addition larger dynamically
 * allocated memory areas.  Allocations exceeding that fixed length must be
 * turned into chains of buffers.  Contiguous allocations that exceed the fixed
 * length are not supported, and (with a single patch to lwIP) should never be
 * made, either.  See the LWIP service's mempool module for more information.
 */
#define MEM_LIBC_MALLOC                 1

#define mem_clib_malloc                 mempool_malloc
#define mem_clib_calloc                 mempool_calloc
#define mem_clib_free                   mempool_free

/* Just in case, as lwIP does not use this definition.  Implement if needed. */
#define mem_clib_realloc                __NOT_IMPLEMENTED

/*
 * Size of a single buffer in the memory pool, in bytes.  This definition is
 * ours, and not used directly by lwIP.  However, we need it here because we
 * derive various limits from this setting.  The current setting should provide
 * a decent trade-off between per-buffer utilization on one hand and the length
 * of buffer chains and queues on the other.  For example, it takes only three
 * buffers to store a full-sized ethernet packet with the current setting.
 * While the value could be lowered, it should remain large enough to ensure
 * that essentially all packet headers fit in a packet's first buffer.  Also
 * note that lowering this value may cause certain other allocations to grow.
 */
#define MEMPOOL_BUFSIZE                 512

/*
 * The following value should be sizeof(void *), but lwIP's own #if-based
 * sanity checks make that impossible.  It is crucial that the value is set to
 * exactly the value of sizeof(void *) though: a value that is too small will
 * cause problems on alignment-enforcing platforms, and a value that is too
 * large will cause lwIP to fail on an assertion.  TODO: 64-bit support.
 */
#define MEM_ALIGNMENT                   4

/*
 * The reason that we use lwIP's pools for its own objects, is that we actually
 * want the separation of pools to avoid allocating too many objects of one
 * type, e.g. wasting all memory on IP fragment reassembly.  As such, we do not
 * want to use our memory pool implementation for those pools, especially since
 * the pool information would be lost if we did.
 */
#define MEMP_MEM_MALLOC                 0

#define MEMP_OVERFLOW_CHECK             0
#define MEMP_SANITY_CHECK               0

/* We do not use pools for custom allocations. */
#define MEM_USE_POOLS                   0
#define MEMP_USE_CUSTOM_POOLS           0

/*
 * We do not use the standard lwIP pbuf pool at all.  The following definitions
 * would both be zero if that didn't make lwIP fail on a static assertion.
 */
#define PBUF_POOL_SIZE                  0
#define PBUF_POOL_BUFSIZE               (MEM_ALIGNMENT + 1)

/*
 * This definition should override lwIP's internal one, resulting in only pbuf
 * chains with PBUF_REF buffers being copied when queuing packets during
 * ARP/NDP queries.  In fact, copying nothing should be safe because both lwIP
 * and our service implementation are zero-copy aware and should never do
 * something that could violate the requirements for no-copy safety.  However,
 * while PBUF_REF buffers may be generated by the IP fragmentation code in a
 * safe manner, lwIP itself may in the future be changed to generate PBUF_REF
 * buffers that are not safe, and it is not very costly to copy them, which is
 * why we test against PBUF_REF here rather than simply putting in "(0)"--i.e.,
 * just to be on the safe side.  For more information, see lwIP patch #9272 and
 * the references mentioned in lwIP's default definition of PBUF_NEEDS_COPY.
 */
#define PBUF_NEEDS_COPY(p)              ((p)->type == PBUF_REF)

#define LWIP_ARP                        1

/*
 * Like many things, the lwIP ARP table is a simple array, with searches using
 * linear lookups.  Thus, while we can afford the memory, increasing this
 * setting will effectively make sending packets slower.  TODO: tune this.
 */
#define ARP_TABLE_SIZE                  16

#define ARP_QUEUEING                    1

/* No VLAN support just yet. */
#define ETHARP_SUPPORT_VLAN             0

/* Deliberately disabled; see ETH_PAD_LEN below. */
#define ETH_PAD_SIZE                    0

#define ETHARP_SUPPORT_STATIC_ENTRIES   1

/*
 * This setting is enabled mainly for the purpose of allowing dhcpcd(8) to
 * implement IPv4 AutoIP support in userspace, because that is the main case
 * where two attached networks may see the same IPv4 addresses.
 */
#define ETHARP_TABLE_MATCH_NETIF        1

/*
 * IPv4 support can not be disabled at any level, and certainly not here.
 */
#define LWIP_IPV4                       1

/*
 * We enable support for forwarding at compile time.  We patch lwIP so that we
 * can control this feature with a setting at run time.
 */
#define IP_FORWARD                      1

#define IP_FRAG                         1

/*
 * Number of helper structures, one per fragment that may be in the process of
 * being sent to a network driver.  We do not expect a whole lot of fragments
 * to be sent at any given time, but one large packet may already require a
 * lot of fragments (e.g. about 44 fragments for one 64K packet fragmented for
 * ethernet), so do not set this too low either.
 */
#define MEMP_NUM_FRAG_PBUF              256

#define IP_REASSEMBLY                   1

/*
 * Number of helper structures, one per packet that is in the process of being
 * reassembled.  This structure is not the smallest and we do not expect lots
 * of concurrent reassembly going on, so keep this fairly low.
 */
#define MEMP_NUM_REASSDATA              16

/*
 * The maximum number of pbufs that may be used for reassembly of fragmented
 * packets.  The following value is required for reassembly of one 64K-sized
 * packet, which is required by one of our tests.
 */
#define IP_REASS_MAX_PBUFS              129

/*
 * We do want to require for sending broadcast packets that the SO_BROADCAST
 * socket option be set on the socket first (IP_SOF_BROADCAST).  We do not want
 * to filter incoming broadcast packets on sockets that do not have that socket
 * option set, though (IP_SOF_BROADCAST_RECV).
 */
#define IP_SOF_BROADCAST                1
#define IP_SOF_BROADCAST_RECV           0

/*
 * For TCP and UDP, lwIP currently iterates through port numbers sequentially
 * when selecting a port.  This option enables at least randomizing the
 * starting port number after start-up, but obviously that is not at all useful
 * for security purposes.  Still, it is better than nothing for the case it
 * aims to cover: likely selection of the same port numbers after each reboot.
 */
#define LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS 1

#define LWIP_ICMP                       1

#define LWIP_MULTICAST_PING             1

#define LWIP_RAW                        1

#define MEMP_NUM_RAW_PCB                16

/* DHCP is handled entirely by dhcpcd(8) in our case. */
#define LWIP_DHCP                       0

/*
 * We let dhcpcd(8) manage automatic IPv4 assignment, too.  We do not support
 * the relevant flags for locally assigned IPv4 addresses (e.g.,
 * IN_IFF_TENTATIVE): we cannot implement them properly since lwIP's AutoIP
 * support is all-or-nothing, and dhcpcd(8) can make do without them as well.
 */
#define LWIP_AUTOIP                     0

#define LWIP_MULTICAST_TX_OPTIONS       1

#define LWIP_IGMP                       1

/*
 * Each interface that supports IGMP also joins the all-nodes multicast group.
 * This is done automatically by lwIP, but there need to be enough entries for
 * this.  The '16' here is the maximum number of interfaces that support
 * multicast, and may have to be increased in the future.  The
 * NR_IPV4_MCAST_GROUP definition is our own, and determines the maximum number
 * of IGMP groups that can be joined on sockets.
 */
#define NR_IPV4_MCAST_GROUP             64

#define MEMP_NUM_IGMP_GROUP             (16 + NR_IPV4_MCAST_GROUP)

#define LWIP_DNS                        0

#define LWIP_UDP                        1

#define MEMP_NUM_UDP_PCB                256

#define LWIP_TCP                        1

/*
 * The maximum number of TCP sockets.  This definition is our own, but it is in
 * effect the main setting that determines how much memory the LWIP service
 * reserves statically for various pools of TCP-related structures.  In all the
 * settings further below and elsewhere, we provision the LWIP service such
 * that it can support full-speed two-way communication for each TCP socket,
 * assuming an application that is built to use sockets efficiently by using
 * large I/O requests.  However, various necessary structures (especially
 * MEMP_NUM_PBUF and MEMP_NUM_TCP_SEG) cannot be allocated dynamically, so we
 * have to preallocate them all for the worst case.  The result is substantial
 * memory usage even when few buffers are in use.  We currently consider this
 * an acceptable trade-off.  However, should the LWIP service's static memory
 * usage become an issue, the best start is to lower this value.
 */
#define NR_TCPSOCK                      256

/*
 * The maximum number of lwIP TCP PCBs.  Each TCP socket (NR_TCPSOCK) needs one
 * of these.  We currently add 50% of them on top of that, for TCP connections
 * in SYN_RCVD and TIME_WAIT state.
 */
#define MEMP_NUM_TCP_PCB                (NR_TCPSOCK * 3 / 2)

/*
 * lwIP uses a separate, smaller PCB for each listening TCP socket.  For us,
 * this is not very convenient, because it means another separate pool of
 * structures and another parameter to tune.  In addition, we have to be
 * careful not to access certain PCB fields of listening TCP PCBs.
 */
#define MEMP_NUM_TCP_PCB_LISTEN         64

/*
 * Unfortunately, lwIP does not support full path MTU discovery.  Therefore, it
 * is important that this value is not too high.  We set it conservatively to
 * the value that the previous lwIP-based TCP/IP service used as well.
 */
#define TCP_MSS                         1460

/*
 * The maximum receive window size for TCP connections.  This value must not be
 * too low, because that would affect TCP performance.  It must also not be too
 * high, because it determines the minimum receive buffer size for TCP
 * connections.  The current setting should be reasonable.
 */
#define TCP_WND                         16384

/*
 * The following setting defines the "send window" size, that is, up to how
 * many bytes lwIP will send without acknowledgment when not constrained by the
 * receiver's window size.  This value should be a multiple of the TCP MSS, or
 * lwIP will send sub-MSS packets even in ideal circumstances.  Unfortunately
 * this is a static definition and thus cannot be a function of the actual MSS
 * of any individual connection, so our hope is that the vast majority of TCP
 * connections end up using the maximum MSS (i.e., the TCP_MSS value), which is
 * probably usually true.  The current definition is as close as possible to
 * 16KB while still a multiple of the MSS.  Note that various memory pool size
 * settings in this file depend on the TCP_SND_BUF value, so increasing this
 * value will also make the LWIP service use more memory.
 */
#define TCP_SND_BUF                     (11 * TCP_MSS)

/*
 * This setting is an artificial limit that can be used to reduce how many
 * buffers can be used for the send queue of a single TCP connection.  We set
 * it such that an application that uses large writes will never hit the limit,
 * while an application that uses small writes will not take up more than its
 * fair share of resources.  The formula is as follows: there can be at most
 * (TCP_SND_BUF / TCP_MSS) maximum-sized segments (11) enqueued, each of which
 * consists of one header pbuf and (ROUND-UP(TCP_MSS / MEMPOOL_BUFSIZE) + 1)
 * references to data (4), yielding a total of 55 pbufs for a full queue.
 * Given that in the very worst case, one single enqueued byte may take two
 * pbufs (one header, one data pbuf), inefficient applications might find
 * themselves unable to enqueue more than half of that number in bytes, i.e.,
 * 27 bytes.  This is exactly as intended: such inefficient senders can not
 * negatively affect other TCP connections, while more of their data will be
 * queued up by the LWIP service, as the default LWIP service send queue (32KB)
 * is about twice the TCP PCB's send queue size (TCP_SND_BUF, ~16KB).  They
 * will simply experience slow communication as a result.
 */
#define TCP_SND_QUEUELEN                ((TCP_SND_BUF / TCP_MSS) * \
                                         ((TCP_MSS + MEMPOOL_BUFSIZE - 1) / \
                                          MEMPOOL_BUFSIZE + 2))

/*
 * This setting defines the number of pbuf structures that can be used to point
 * to data elsewhere (PBUF_ROM, PBUF_REF).  They are used by the lwIP TCP
 * module, the lwIP fragmentation code, and by our ethernet interface module.
 * These structures are small, and we need a lot of them.  In particular, we
 * need one PBUF_ROM structure for each contiguous stretch of data on the send
 * queue of a lwIP TCP PCB.  For this we take the maximum we need to fill a TCP
 * PCB's send queue, and multiply it by the supported number of TCP sockets.
 * The maximum we need is the number of references we need per segment, times
 * the number of segments.  For simplicity we base this computation on the
 * PCB_SND_QUEUELEN computation; see its definition for details.  The result
 * should be 44 references per TCP connection right now.  In addition to that,
 * the ethif module uses PBUF_REF structures for packets enqueued for sending.
 * For that reason, we add another MEMP_NUM_TCP_PCB structures to be able to
 * enqueue at least one packet per TCP PCB at all times.
 */
#define MEMP_NUM_PBUF                   ((TCP_SND_QUEUELEN - (TCP_SND_BUF / \
                                          TCP_MSS)) * NR_TCPSOCK + \
                                         MEMP_NUM_TCP_PCB)

/*
 * The maximum number of TCP segments.  Like the PBUF_REF/PBUF_ROM structures,
 * these are small, but we need a lot of these as well.  We allocate as many
 * segment structures as are needed to fill each TCP socket's send queue, which
 * is in this case bounded by TCP_SND_QUEUELEN (see above).  In theory, there
 * could be one segment per queued piece of data.  Each segment also has a
 * separate header, thus a segment takes a minimum of two pbufs.  This means
 * that we need (TCP_SND_QUEUELEN / 2) segment structures (27) per TCP socket.
 * For sane applications this will never be a real limitation: they should use
 * fewer than half of these at most (11, from TCP_SND_BUF).  Less-than-sane
 * applications can still not eat up more than their fair share.
 */
#define MEMP_NUM_TCP_SEG                ((TCP_SND_QUEUELEN / 2) * NR_TCPSOCK)

#define TCP_LISTEN_BACKLOG              1

/*
 * TCP support for oversized buffers is relevant only for the case that the
 * core TCP module is made responsible for copying data to its own buffers.  We
 * pass our own buffers to the core TCP API, while retaining their ownership.
 * Therefore, this option is useless for us.
 */
#define TCP_OVERSIZE                    0

/*
 * We are currently using the callback API only because the event API has been
 * having problems, but these should now be fixed in lwIP.  The event API has
 * the advantage that it saves 20 bytes per TCP PCB.  TODO: switch over.
 */
#define LWIP_EVENT_API                  0
#define LWIP_CALLBACK_API               1

/* We do not support TCP window scaling at this time. */

/*
 * We would like to align TCP/IP header field accesses to 32 bits.  lwIP offers
 * ETH_PAD_SIZE to that end.  We do not use that however, because it is
 * inconvenient: it adds the padding to the actual output packets, thus forcing
 * our ethif module to correct for that by adjusting its headers.  That does
 * not combine well with our approach of simply increasing the reference count
 * of the output packets so that we can send them later.  Instead, we use our
 * own padding method: we add two bytes to the link header here, and we simply
 * chip the first two bytes off each packet buffer before receiving an incoming
 * packet into it.
 */
/* These two definitions are entirely our own.  They are not used by lwIP. */
#define ETH_PAD_LEN                     2
#define ETH_HDR_LEN                     14

/* Note that VLAN support would require an extra four bytes here. */
#define PBUF_LINK_HLEN                  (ETH_PAD_LEN + ETH_HDR_LEN)

#define PBUF_LINK_ENCAPSULATION_LEN     0

/*
 * We use the status callback to detect lwIP-initiated state changes on local
 * IPv6 addresses.
 */
#define LWIP_NETIF_STATUS_CALLBACK      1

/*
 * This setting simply adds a field to the netif structure that can then be
 * used by lwIP's own modules.  It requires no support from us.
 */
#define LWIP_NETIF_HWADDRHINT           1

/*
 * We provide loopback functionality ourselves, so we do not need the netif
 * layer to duplicate this poorly (e.g., without BPF or statistics support).
 * Moreover, enabling this setting would force loopback traffic over non-
 * loopback interfaces in some scenarios, since we do not enable
 * LWIP_HAVE_LOOPIF either.
 */
#define LWIP_NETIF_LOOPBACK             0

#define LWIP_NETCONN                    0
#define LWIP_SOCKET                     0

#define LWIP_TCP_KEEPALIVE              1

/*
 * lwIP's SO_REUSEADDR semantics are somewhat different from BSD's.  There is
 * more work to be done here.
 */
#define SO_REUSE                        1
#define SO_REUSE_RXTOALL                1

/* We maintain our own, simpler statistics. */
#define LWIP_STATS                      0

#define LWIP_CHECKSUM_CTRL_PER_NETIF    1
#define CHECKSUM_GEN_IP                 1
#define CHECKSUM_GEN_UDP                1
#define CHECKSUM_GEN_TCP                1
#define CHECKSUM_GEN_ICMP               1
#define CHECKSUM_GEN_ICMP6              1
#define CHECKSUM_CHECK_IP               1
#define CHECKSUM_CHECK_UDP              1
#define CHECKSUM_CHECK_TCP              1
#define CHECKSUM_CHECK_ICMP             1
#define CHECKSUM_CHECK_ICMP6            1

/*
 * The checksum-on-copy setting is beneficial only when lwIP does most of the
 * memory copying, and detrimental otherwise.  We do most copying ourselves.
 */
#define LWIP_CHECKSUM_ON_COPY           0

/*
 * During testing, checksum algorithm #3 had slightly better performance than
 * default checksum algorithm #2.
 */
#define LWIP_CHKSUM_ALGORITHM           3

/*
 * IPv6 support is always enabled, even when the system is built with the
 * USE_INET6 setting disabled.  A lot of ugly changes would be required in the
 * service to support disabling LWIP_IPV6, and it is increasingly unlikely that
 * anyone would want to disable USE_INET6 at all.
 */
#define LWIP_IPV6                       1

/*
 * IPv6 scopes support is absolutely necessary for correctness.  Leave the
 * debugging support enabled too, because the scopes support is one of our
 * additions to lwIP and so we want to know if it breaks in the future.
 */
#define LWIP_IPV6_SCOPES                1
#define LWIP_IPV6_SCOPES_DEBUG          1

/*
 * We need an absolute minimum of three IPv6 addresses per interface in order
 * to allow the following typical use case:
 *
 * - one link-local address;
 * - one preferred global address;
 * - one deprecated global address.
 *
 * For some use cases, this limit may not be high enough: for example, it
 * leaves no room for combining permanent and temporary addresses, both of
 * which may have one preferred and one deprecated address.  We currently set
 * the number to four here for pragmatic reasons though: while the first IPv6
 * address slot is always reserved for a link-local address, test93 currently
 * needs to be able to set three global addresses on a single interface for
 * testing purposes.  Setting the number to three will save a bit of memory and
 * computation, but stop test93 from working.
 */
#define LWIP_IPV6_NUM_ADDRESSES         4

/*
 * We enable support for forwarding at compile time.  We patch lwIP so that we
 * can control this feature with a setting at run time.
 */
#define LWIP_IPV6_FORWARD               1

#define LWIP_IPV6_FRAG                  1
#define LWIP_IPV6_REASS                 1

/*
 * This setting is required on 64-bit platforms and does not cost all that much
 * on 32-bit platforms, so we might as well turn it on already.
 */
#define IPV6_FRAG_COPYHEADER            1

/*
 * Since IPv6 address configuration is handled by userland (see below), we do
 * not need lwIP to send router solicitations itself, either.  lwIP will only
 * passively obtain information from router advertisements as they come in.
 * Disabling this option is also necessary for the USE_IPV6=0 case.
 */
#define LWIP_IPV6_SEND_ROUTER_SOLICIT   0

/*
 * We only support IPv6 stateless autoconfiguration through external SLAAC or
 * DHCPv6 clients.  In practice, autoconfiguration is and should be handled
 * excluslvely by dhcpcd(8).  This option must therefore be disabled in order
 * to prevent lwIP from (e.g.) updating address lifetimes on its own.
 */
#define LWIP_IPV6_AUTOCONFIG            0

/*
 * Support for address lifetimes is however absolutely essential for dhcpcd(8)
 * and also needed to support various ifconfig(8) options.
 */
#define LWIP_IPV6_ADDRESS_LIFETIMES     1

/*
 * For safety, use at least a few DAD probes before deciding an address is not
 * duplicated.  This should also guarantee that at least some of them are sent
 * after joining the solicited-node multicast group for the address (the fact
 * that this is not guaranteed is a lwIP bug).  This setting does affect the
 * system startup time, though.
 */
#define LWIP_IPV6_DUP_DETECT_ATTEMPTS   3

#define LWIP_ICMP6                      1

/*
 * MLD is required for IPv6 multicast support.  Basic multicast support is
 * required for IPv6 anyway, and disabling MLD would mean we have to accept all
 * multicast traffic instead of being able to give a specific list to drivers.
 */
#define LWIP_IPV6_MLD                   1

/*
 * Each locally assigned IPv6 address requires joining its corresponding
 * solicited-node multicast group.  This is done automatically by lwIP, but
 * there need to be enough entries for this.  The '16' here is the maximum
 * number of interfaces that support multicast, and may have to be increased in
 * the future.  The NR_IPV6_MCAST_GROUP definition is our own, and determines
 * the maximum number of MLD groups that can be joined on sockets.
 */
#define NR_IPV6_MCAST_GROUP             64

#define MEMP_NUM_MLD6_GROUP             (16 * LWIP_IPV6_NUM_ADDRESSES + \
                                         NR_IPV6_MCAST_GROUP)

#define LWIP_ND6_QUEUEING               1

/* Same as with ARP.  TODO: tune these. */
#define LWIP_ND6_NUM_NEIGHBORS          16
#define LWIP_ND6_NUM_DESTINATIONS       16

/*
 * We disable Router Advertisement message processing, so the prefix and
 * default-router tables are both unused.  We cannot set these values to zero,
 * but we set them to the lowest possible value.  Not that it saves much..
 */
#define LWIP_ND6_NUM_PREFIXES           1
#define LWIP_ND6_NUM_ROUTERS            1

/*
 * Hooks are in a separate file, to allow some of their parameter types to be
 * defined.
 */
#define LWIP_HOOK_FILENAME "lwiphooks.h"

#endif /* !LWIP_LWIPOPTS_H */
